using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using AD.Pms.Core.ClientApi;
using AD.Pms.Core.EnumHelper;
using AD.Pms.DataBase.Models.ZC_Member;
using AD.Pms.DataBase.Models.ZC_Order;
using AD.Pms.Service.DtoModel;
using AD.Pms.Service.Interfaces;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace AD.Pms.Service.Manager
{
    public class PushService : IPushService
    {
        private readonly ZC_MemberContext _zCMemberContext;
        private readonly ZC_OrderContext _zcOrderContext;
        private readonly IHttpClientFactory _httpClientFactory;
        private readonly ILogger _logger;

        public PushService(ZC_MemberContext zcMemberContext, ZC_OrderContext zcOrderContext,
            IHttpClientFactory httpClientFactory, ILogger<PushService> logger)
        {
            _zCMemberContext = zcMemberContext;
            _zcOrderContext = zcOrderContext;
            _httpClientFactory = httpClientFactory;
            _logger = logger;
        }

        public async Task<Tuple<string, string>> GetCaptchaAsync()
        {
            var client = _httpClientFactory.CreateClient();
            var content =
                await client.GetStringAsync("http://open.jinyongci.com/utility/Captcha/GetCaptcha?len=4&type=1");
            JObject jobj = JsonConvert.DeserializeObject(content) as JObject;
            if (jobj != null && string.Equals("200", jobj["code"]?.ToString()))
            {
                return Tuple.Create(jobj["data"].ToString(), jobj["code"].ToString());
            }
            else
            {
                return Tuple.Create(jobj["message"].ToString(), "");
            }
        }

        public async Task<PaginatedList<TblUserAccount>> GetUserAccountByPushUserTypeAsync(PushUserType pushtype,
            int pageindex = 1, int pagesize = 20)
        {
            int maxuserid = 0;
            if (pushtype == PushUserType.RegisteredUsers)
            {
                var result = _zCMemberContext.TblUserAccount.OrderBy(x => x.Pkid);
                var page = await PaginatedList<TblUserAccount>.CreateAsync(result, pageindex, pagesize);
                return page;
            }
            else if (pushtype == PushUserType.PayedUsers)
            {
                var result = from u in _zCMemberContext.TblUserAccount
                    join o in _zcOrderContext.TblPayInfo on u.UserId equals o.UserId
                    where !(o.IsDelete.HasValue && o.IsDelete.Value) && !(u.IsDelete.HasValue && u.IsDelete.Value)
                    select u;
                var page = await PaginatedList<TblUserAccount>.CreateAsync(result, pageindex, pagesize);
                return page;
            }
            else if (pushtype == PushUserType.WillExpireUsers)
            {
                var result = from u in _zCMemberContext.TblUserAccount
                    join o in _zCMemberContext.TblUserPermission on u.UserId equals o.UserId
                    where !(o.IsDelete.HasValue && o.IsDelete.Value) && !(u.IsDelete.HasValue && u.IsDelete.Value)
                    select u;
                var page = await PaginatedList<TblUserAccount>.CreateAsync(result, pageindex, pagesize);
                return page;
            }
            else
            {
                throw new NotSupportedException();
            }
        }

        public async Task<bool> PushByUserAccountInfoAsync(IEnumerable<TblUserAccount> userAccounts, string content,
            string codeid,
            string ip, string code, PushType pushType)
        {
            if (userAccounts == null || !userAccounts.Any())
            {
                return false;
            }

            var replacement = GetReplacement(content);
            if (replacement.Any())
            {
                Func<string, TblUserAccount, string> GetReplaceContent = (c, u) =>
                {
                    var temp = c;
                    foreach (var replace in replacement)
                    {
                        if (string.Equals(replace, "{{username}}"))
                        {
                            temp = temp.Replace("{{username}}", u.UserName);
                        }

                        if (string.Equals(replace, "{{phone}}"))
                        {
                            temp = temp.Replace("{{phone}}", u.Phone);
                        }
                    }

                    return temp;
                };
                var tasks = userAccounts.Select(x =>
                {
                    var data = GetReplaceContent(content, x);
                    return PushByContentAsync(new[] {x}, pushType, code, data, codeid, ip);
                });
                var result = await Task.WhenAll(tasks);
                return result.All(x => x);
            }
            else
            {
                var result = await PushByContentAsync(userAccounts, pushType, code, content, codeid, ip);
                return result;
            }
        }

        public async Task<bool> PushSMSByContentAsync(IEnumerable<string> phones, string code, string content,
            string codeid,
            string ip)
        {
            var data = new Dictionary<string, object>()
            {
                {"phone", phones},
                {"code", code},
                {"codeid", codeid},
                {"type", "0"},
                {"message", content},
                {"ip", ip}
            };
            var client = _httpClientFactory.CreateClient();
            var response = await client.PostAsJsonAsync("http://open.jinyongci.com/utility/sms/sendMsg", data);
            if (response.IsSuccessStatusCode)
            {
                JObject jobj = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()) as JObject;
                if (jobj != null && string.Equals("200", jobj["code"]?.ToString()))
                {
                    return true;
                }

                return false;
            }

            return false;
        }


        public async Task<bool> PushSMSCodeAsync(string phone, string code,
            string codeid,
            string ip)
        {
            var data = new Dictionary<string, object>()
            {
                {"phone", phone},
                {"code", code},
                {"codeid", codeid},
                {"type", "0"},
                {"ip", ip}
            };
            var client = _httpClientFactory.CreateClient();
            var response = await client.PostAsJsonAsync("http://open.jinyongci.com/utility/sms/sendCode", data);
            if (response.IsSuccessStatusCode)
            {
                JObject jobj = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()) as JObject;
                if (jobj != null && string.Equals("200", jobj["code"]?.ToString()))
                {
                    return true;
                }

                return false;
            }

            return false;
        }

        public async Task<bool> PushByContentAsync(IEnumerable<TblUserAccount> userAccounts,
            PushType pushType,
            string code, string content,
            string codeid,
            string ip)
        {
            if (pushType == PushType.SMS)
            {
                var result = await PushSMSByContentAsync(userAccounts.Select(x => x.Phone), code, content, codeid, ip);
                return result;
            }
            else
            {
                var messages = userAccounts.Select(x => new TblUserMessage()
                {
                    Detail = content,
                    UserId = x.UserId,
                    IsRead = false,
                    IsDelete = false,
                    CreateTime = DateTime.Now,
                    UpdateTime = DateTime.Now
                });
                await _zCMemberContext.TblUserMessage.AddRangeAsync(messages);
                return true;
            }
        }

        private IEnumerable<string> GetReplacement(string content)
        {
            Regex re = new Regex(@"\{\{\w+\}\}");
            var matchs = re.Matches(content);
            return matchs.Select(x => x.Value);
        }
    }
}